#include "stdafx.h"
#include "TextTestResult.h"
#include "CppUnitException.h"
#include "Test.h"
#include "eString.h"
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cctype>

namespace JHCPP{
	namespace CppUnit {

		CTextTestResult::CTextTestResult() : m_ostr(std::cout)
		{
			setup();
		}

		CTextTestResult::CTextTestResult(std::ostream& ostr):m_ostr(ostr)
		{
			setup();
		}

		void CTextTestResult::setup()
		{
		#if !defined(_WIN32_WCE)
			const char* env = std::getenv("CPPUNIT_IGNORE");
			if (env)
			{
				std::string ignored = env;
				std::string::const_iterator it = ignored.begin();
				std::string::const_iterator end = ignored.end();
				while (it != end)
				{
					while (it != end && std::isspace(*it)) ++it;
					std::string test;
					while (it != end && !std::isspace(*it)) test += *it++;
					if (!test.empty()) m_ignored.insert(test);
				}
			}
		#endif
		}

		void CTextTestResult::addError(CTest* test, CCppUnitException* e)
		{
			if (m_ignored.find(test->toString()) == m_ignored.end())
			{
				CTestResult::addError(test, e);
				m_ostr << "ERROR" << std::flush;
			}
			else
			{
				m_ostr << "ERROR (ignored)" << std::flush;
			}
		}

		void CTextTestResult::addFailure(CTest* test, CCppUnitException* e)
		{
			if (m_ignored.find(test->toString()) == m_ignored.end())
			{
				CTestResult::addFailure(test, e);
				m_ostr << "FAILURE" << std::flush;
			}
			else
			{
				m_ostr << "FAILURE (ignored)" << std::flush;
			}
		}

		void CTextTestResult::startTest(CTest* test)
		{
			CTestResult::startTest(test);
			m_ostr << "\n" << shortName(test->toString()) << ": ";
		}

		void CTextTestResult::printErrors(std::ostream& stream)
		{
			if (testErrors() != 0) 
			{
				stream << "\n";

				if (testErrors() == 1)
					stream << "There was " << testErrors() << " error: " << std::endl;
				else
					stream << "There were " << testErrors() << " errors: " << std::endl;

				int i = 1;
				for (std::vector<CTestFailure*>::iterator it = errors().begin(); it != errors().end(); ++it)
				{
					CTestFailure* failure = *it;
					CCppUnitException* e = failure->thrownException();

					stream << std::setw(2) << i
						   << ": "
						   << failure->failedTest()->toString() << "\n"
						   << "    \"" << (e ? e->what() : "") << "\"\n"
						   << "    in \"" 
						   << (e ? e->fileName() : std::string())
						   << "\", line ";
					if (e == 0)
					{
						stream << "0";
					}
					else
					{
						stream << e->lineNumber();
						if (e->data2LineNumber() != CCppUnitException::CPPUNIT_UNKNOWNLINENUMBER)
						{
							stream << " data lines " << e->data1LineNumber()
													   << ", " << e->data2LineNumber();
						}
						else if (e->data1LineNumber() != CCppUnitException::CPPUNIT_UNKNOWNLINENUMBER)
						{
							stream << " data line " << e->data1LineNumber();
						}
					}
					stream << "\n";
					i++;
				}
			}
		}

		void CTextTestResult::printFailures(std::ostream& stream)
		{
			if (testFailures() != 0)
			{
				stream << "\n";
				if (testFailures() == 1)
					stream << "There was " << testFailures() << " failure: " << std::endl;
				else
					stream << "There were " << testFailures() << " failures: " << std::endl;

				int i = 1;

				for (std::vector<CTestFailure*>::iterator it = failures().begin(); it != failures().end(); ++it)
				{
					CTestFailure* failure = *it;
					CCppUnitException* e = failure->thrownException();

					stream << std::setw(2) << i
						   << ": "
						   << failure->failedTest()->toString() << "\n"
						   << "    \"" << (e ? e->what() : "") << "\"\n"
						   << "    in \"" 
						   << (e ? e->fileName() : std::string())
						   << "\", line ";
					if (e == 0)
					{
						stream << "0";
					}
					else
					{
						stream << e->lineNumber();
						if (e->data2LineNumber() != CCppUnitException::CPPUNIT_UNKNOWNLINENUMBER)
						{
							stream << " data lines " 
								   << e->data1LineNumber()
								   << ", " << e->data2LineNumber();
						}
						else if (e->data1LineNumber() != CCppUnitException::CPPUNIT_UNKNOWNLINENUMBER)
						{
							stream << " data line " << e->data1LineNumber();
						}
					}
					stream << "\n";
					i++;
				}
			}
		}

		void CTextTestResult::print(std::ostream& stream)
		{
			printHeader(stream);
			printErrors(stream);
			printFailures(stream);
		}

		void CTextTestResult::printHeader(std::ostream& stream)
		{
			stream << "\n\n";
			if (wasSuccessful())
				stream << "OK (" 
						  << runTests() << " tests)" 
						  << std::endl;
			else
				stream << "!!!FAILURES!!!" << std::endl
						  << "Runs: "
						  << runTests ()
						  << "   Failures: "
						  << testFailures ()
						  << "   Errors: "
						  << testErrors ()
						  << std::endl;
		}

		std::string CTextTestResult::shortName(const std::string& testName)
		{
			std::string::size_type pos = testName.rfind('.');
			if (pos != std::string::npos)
				return std::string(testName, pos + 1);
			else
				return testName;
		}

	}//end of namespace CppUnit
}//end of namespace JHCPP
